use crate::chunk_type::ChunkType;
use crate::Error;               
use crc::Crc;                   // crc crate
use crc::CRC_32_ISO_HDLC;       // PNG 规范所用的 CRC-32 算法常量
use std::convert::TryFrom;
use std::fmt;
/// 一个 PNG Chunk，由：chunk_type（4 字节）、data（实际长度）和预先计算好的 crc（4 字节）组成。
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Chunk {
    chunk_type: ChunkType,
    data: Vec<u8>,
    crc: u32,
}

impl Chunk {
    /// 用于外部调用的构造函数：给定 ChunkType 和 data，自动计算 CRC-32
    pub fn new(chunk_type: ChunkType, data: Vec<u8>) -> Chunk {
        // 先把 chunk_type 的 4 字节与 data 合并为一个临时 Vec<u8>，用于计算 CRC
        let mut bytes_for_crc: Vec<u8> = Vec::with_capacity(4 + data.len());
        bytes_for_crc.extend_from_slice(&chunk_type.bytes()); // chunk type 的 4 字节
        bytes_for_crc.extend_from_slice(&data);               // data 部分

        // 使用 crc crate 计算 CRC-32
        let crc_calculator = Crc::<u32>::new(&CRC_32_ISO_HDLC);
        let computed_crc: u32 = crc_calculator.checksum(&bytes_for_crc);

        Chunk {
            chunk_type,
            data,
            crc: computed_crc,
        }
    }

    /// 返回 data 的长度，也就是 Chunk 中的 Length 字段
    pub fn length(&self) -> u32 {
        self.data.len() as u32
    }

    /// 返回对外可见的 ChunkType 引用
    pub fn chunk_type(&self) -> &ChunkType {
        &self.chunk_type
    }

    /// 返回对外可见的 data 引用
    pub fn data(&self) -> &[u8] {
        &self.data
    }

    /// 返回保存在这个 Chunk 里的 CRC 值
    pub fn crc(&self) -> u32 {
        self.crc
    }

    /// 如果 data 部分是合法 UTF-8，就返回转换后的 String，否则返回 Err
    pub fn data_as_string(&self) -> Result<String, Error> {
        // 使用 String::from_utf8 可以把 Vec<u8> 转为 String
        // 但这里 data() 返回的是 &[u8]，所以先拷贝或用 to_vec()
        match String::from_utf8(self.data.clone()) {
            Ok(s) => Ok(s),
            Err(e) => Err(format!("Chunk data is not valid UTF-8: {}", e).into()),
        }
    }

    /// 按照 PNG 规范，把整个 chunk 序列化为一个 Vec<u8>：
    ///   4 字节 Length（big‐endian） + 4 字节 Chunk Type + data + 4 字节 CRC（big‐endian）
    pub fn as_bytes(&self) -> Vec<u8> {
        // 计算 length 的 big‐endian 表示
        let length_bytes = self.length().to_be_bytes(); // [u8; 4]

        // chunk_type 的 4 字节
        let chunk_type_bytes = self.chunk_type.bytes(); // [u8; 4]

        // data 部分
        let data_bytes = &self.data; // &[u8]

        // crc 的 big‐endian 表示
        let crc_bytes = self.crc.to_be_bytes(); // [u8; 4]

        // 合并所有部分
        let mut result: Vec<u8> = Vec::with_capacity(4 + 4 + data_bytes.len() + 4);
        result.extend_from_slice(&length_bytes);
        result.extend_from_slice(&chunk_type_bytes);
        result.extend_from_slice(data_bytes);
        result.extend_from_slice(&crc_bytes);

        result
    }
}

impl TryFrom<&[u8]> for Chunk {
    type Error = Error;

    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
        // 1. 至少要有 12 字节（即 length=0 时的最短 chunk）
        if bytes.len() < 12 {
            return Err("Chunk 太短，至少要 12 字节".into());
        }

        // 2. 读长度字段
        let length = u32::from_be_bytes(bytes[0..4].try_into().unwrap()) as usize;
        let total_len = 4 + 4 + length + 4;

        // 3. 如果剩下的字节不足以构成整个 chunk，就报错
        if bytes.len() < total_len {
            return Err(format!(
                "Chunk 声明 data 长度 {}，但剩余字节只有 {}",
                length,
                bytes.len() - 8
            ).into());
        }

        // 4. 解析 chunk type
        let chunk_type_bytes: [u8; 4] = bytes[4..8]
            .try_into()
            .map_err(|_| "Failed to parse chunk type bytes".to_string())?;
        let chunk_type = ChunkType::try_from(chunk_type_bytes)?;

        // 5. 拷贝 data
        let data = bytes[8..(8 + length)].to_vec();

        // 6. 读取文件中的 CRC
        let crc_read_bytes: [u8; 4] = bytes[(8 + length)..(8 + length + 4)]
            .try_into()
            .map_err(|_| "Failed to parse CRC bytes".to_string())?;
        let crc_read = u32::from_be_bytes(crc_read_bytes);
        
        // 7. 计算实际 CRC（包含 type 和 data 部分）
        let crc_calculator = Crc::<u32>::new(&crc::CRC_32_ISO_HDLC);
        let mut digest = crc_calculator.digest();
        digest.update(&bytes[4..(8 + length)]);
        let crc_computed = digest.finalize();
        if crc_read != crc_computed {
            return Err(format!(
                "CRC 不匹配：文件写入 {:#x}，实测 {:#x}",
                crc_read, crc_computed
            ).into());
        }

        // 8. 构造并返回 Chunk
        Ok(Chunk {
            chunk_type,
            data,
            crc: crc_read,
        })
    }
}

/// 实现 Display，让 `format!("{}", chunk)` 能编译通过
impl fmt::Display for Chunk {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // 这里只要能跑通 write! 就足够，测试中不对输出做验证
        write!(
            f,
            "{} (length: {}, crc: 0x{:08X})",
            self.chunk_type,
            self.length(),
            self.crc
        )
    }
}


#[cfg(test)]
mod tests {
    use super::*;
    use crate::chunk_type::ChunkType;
    use std::str::FromStr;

    /// 辅助函数：构造一个有效的 chunk 字节数据
    fn testing_chunk() -> Chunk {
        let data_length: u32 = 42;
        let chunk_type = "RuSt".as_bytes(); // 4 字节
        let message_bytes = b"This is where your secret message will be!";
        let crc: u32 = 2882656334; // 0xACF824B6

        // 按 PNG 顺序：length(4) + chunk_type(4) + data(42) + crc(4)
        let chunk_data: Vec<u8> = data_length
            .to_be_bytes()
            .iter()
            .chain(chunk_type.iter())
            .chain(message_bytes.iter())
            .chain(crc.to_be_bytes().iter())
            .copied()
            .collect();

        Chunk::try_from(chunk_data.as_ref()).unwrap()
    }

    #[test]
    fn test_new_chunk() {
        let chunk_type = ChunkType::from_str("RuSt").unwrap();
        let data = b"This is where your secret message will be!".to_vec();
        let chunk = Chunk::new(chunk_type, data);
        assert_eq!(chunk.length(), 42);
        assert_eq!(chunk.crc(), 2882656334);
    }

    #[test]
    fn test_chunk_length() {
        let chunk = testing_chunk();
        assert_eq!(chunk.length(), 42);
    }

    #[test]
    fn test_chunk_type() {
        let chunk = testing_chunk();
        assert_eq!(chunk.chunk_type().to_string(), String::from("RuSt"));
    }

    #[test]
    fn test_chunk_string() {
        let chunk = testing_chunk();
        let chunk_string = chunk.data_as_string().unwrap();
        let expected_chunk_string =
            String::from("This is where your secret message will be!");
        assert_eq!(chunk_string, expected_chunk_string);
    }

    #[test]
    fn test_chunk_crc() {
        let chunk = testing_chunk();
        assert_eq!(chunk.crc(), 2882656334);
    }

    #[test]
    fn test_valid_chunk_from_bytes() {
        let data_length: u32 = 42;
        let chunk_type = "RuSt".as_bytes(); // 4 字节
        let message_bytes = b"This is where your secret message will be!";
        let crc: u32 = 2882656334; // 正确的 CRC

        let chunk_data: Vec<u8> = data_length
            .to_be_bytes()
            .iter()
            .chain(chunk_type.iter())
            .chain(message_bytes.iter())
            .chain(crc.to_be_bytes().iter())
            .copied()
            .collect();

        let chunk = Chunk::try_from(chunk_data.as_ref()).unwrap();
        let chunk_string = chunk.data_as_string().unwrap();
        let expected_chunk_string = String::from("This is where your secret message will be!");
        assert_eq!(chunk.length(), 42);
        assert_eq!(chunk.chunk_type().to_string(), String::from("RuSt"));
        assert_eq!(chunk_string, expected_chunk_string);
        assert_eq!(chunk.crc(), 2882656334);
    }

    #[test]
    fn test_invalid_chunk_from_bytes() {
        let data_length: u32 = 42;
        let chunk_type = "RuSt".as_bytes();
        let message_bytes = b"This is where your secret message will be!";
        let crc: u32 = 2882656333; // 故意写错一个数

        let chunk_data: Vec<u8> = data_length
            .to_be_bytes()
            .iter()
            .chain(chunk_type.iter())
            .chain(message_bytes.iter())
            .chain(crc.to_be_bytes().iter())
            .copied()
            .collect();

        let chunk = Chunk::try_from(chunk_data.as_ref());
        assert!(chunk.is_err());
    }

    #[test]
    pub fn test_chunk_trait_impls() {
        let data_length: u32 = 42;
        let chunk_type = "RuSt".as_bytes();
        let message_bytes = b"This is where your secret message will be!";
        let crc: u32 = 2882656334;

        let chunk_data: Vec<u8> = data_length
            .to_be_bytes()
            .iter()
            .chain(chunk_type.iter())
            .chain(message_bytes.iter())
            .chain(crc.to_be_bytes().iter())
            .copied()
            .collect();

        let chunk: Chunk = TryFrom::try_from(chunk_data.as_ref()).unwrap();

        let _chunk_string = format!("{}", chunk);
    }
}
